#ifndef __CAPAFISICA_MANEJADORESPACIOLIBRE_H
#define __CAPAFISICA_MANEJADORESPACIOLIBRE_H

/******************************************************************************
 *                     Organizacion de Datos - 75.06                          *
 *                         Catedra Lic. Servetto                              *
 *            Facultad de Ingenieria - Universidad de Buenos Aires            *
 ******************************************************************************/

#define MAX_NUM_REGISTERS 40960
#define MAX_NUMBLOCKS 10240

#include <string>
#include <fstream>

using namespace std;

namespace CapaFisica
{
	
	/// Clase abstracta que provee el manejo basico de archivos de control de texto para el control de espacio libre en un archivo. Determina la interfaz que debe implementar un Manejador de Espacio Libre especefico.
	class ManejadorEspacioLibre
	{
		
		protected:	
		
		// Archivo de texto con informacion de control.
		fstream file;
		// Convierte un entero a su representacion en cadena de caracteres.
		char* EnteroAString(int c, char digitos);
		// Convierte una cadena de caracteres que representa a un entero a su tipo correspondiente.
		int StringAEntero(char* c);		
		// Convierte un digito a su representacion ASCII.
		char DigitoACaracter(char c);
		// Convierte un digito en formato ASCII a su tipo correspondiente.
		char CaracterADigito(char c);	
		// Metodo protegido abstracto que inicializa el manejador de espacio libre.
		virtual void Inicializar() = 0;
		
		public:
		
		/// Construye un ManejadorEspacioLibre inicializado un archivo donde guardarlo.
		/// @param clase Nombre de la clase que representa al archivo a manejar. Se utiliza como clave en toda la capa fisica.
		ManejadorEspacioLibre(string clase);
		
		/// Destruye un ctor ManejadorEspacioLibre y libera todos los recursos utilizados.
		virtual ~ManejadorEspacioLibre();
		
		/// Metodo abstracto que indica si el grupo esta libre para ser utilizado.
		/// @param grupoId Identificador entero del grupo consultado.
		/// @return true si esta libre, false en caso contrario.
		virtual bool EstaLibre(int grupoId) = 0;
		
		/// Metodo abstracto que indica si el grupo esta inicializdo, si no lo esta, todos los demas bloques con grupoId superior tampoco lo estaran.
		/// @param grupoId Identificador entero del grupo consultado.
		/// @return true si esta inicializado, false en caso contrario.
		virtual bool EstaInicializado(int grupoId) = 0;

		/// Metodo abstracto que permite especificar un grupo como libre.
		/// @param grupoId Identificador entero del grupo liberado. 
		virtual void Liberar(int grupoId) = 0;
		
		/// Metodo abstracto que devuelve el tamanio actual del grupo.
		/// @param grupoId Identificador entero del grupo consultado. 
		/// @return El tamanio del bloque, en bytes.
		virtual int ObtenerTamanio(int grupoId) = 0;
		
		/// Metodo abstracto que reasigna el tamanio de espacio libre destinado a un grupo.
		/// @param grupoId Identificador entero del grupo a actualizarle el tamanio libre.
		/// @param nuevoTamanio Nuevo tamaño libre asignado a ese grupo.
		virtual void AsignarTamanio(int grupoId, int nuevoTamanio) = 0;
		
		/// Metodo abstracto que devuelve el tamanio actual del archivo entero.
		/// @return El tamanio del archivo donde se guarda el espacio libre.
		virtual long ObtenerTamanioArchivo() = 0;
		
		/// Metodo abstracto que devuelve un identificador que se encuentre libre para ser utilizado.
		/// @param tamanio Tamanio inicial del bloque pedido. 
		/// @return Id del bloque libre obtenido.
		virtual int ObtenerBloqueLibre(int tamanio) = 0;
		
		/// Metodo abstracto que persististe en disco la informacion del ManejadorEspacioLibre.
		/// @param grupoId Identificador entero del grupo liberado. 
		virtual void GuardarArchivo()= 0;
		
	};

	/// Implementa un mapa de bits a traves de la interfaz de la clase abstracta ManajadorEspacioLibre.
	class MapaDeBits : public ManejadorEspacioLibre
	{
		
		private:
		
		int tamanioRegistro;
		short elementos[MAX_NUM_REGISTERS];
		void Inicializar();	
		
		public:
		
		/// Construye una instancia de un manejador de espacio libre basado en la tecnica de mapa de bits.
		/// @param clase Nombre de la clase que representa al archivo a manejar. Se utiliza como clave en toda la capa fisica.
		/// @param tamanioRegistro Tamanio fijo de cada registro presente en el archivo controlado.
		MapaDeBits(string clase, int tamanioRegistro);
		
		/// Destruye una instancia del MapaDeBits y libera todos los recursos.
		~MapaDeBits();
		
		// Metodos que implementan los metodos abstractos de ManejadorEspacioLibre
		
		/// Metodo que indica si el grupo esta libre para ser utilizado.
		/// @param grupoId Identificador entero del grupo consultado.
		/// @return true si esta libre, false en caso contrario.
		virtual bool EstaLibre(int grupoId);
		
		/// Metodo que indica si el grupo esta inicializdo, si no lo esta, todos los demas bloques con grupoId superior tampoco lo estaran.
		/// @param grupoId Identificador entero del grupo consultado.
		/// @return true si esta inicializado, false en caso contrario.
		virtual bool EstaInicializado(int grupoId);
		
		/// Metodo que permite especificar un grupo como libre.
		/// @param grupoId Identificador entero del grupo liberado. 
		void Liberar(int grupoId);
		
		/// Metodo que devuelve el tamanio actual del grupo.
		/// @param grupoId Identificador entero del grupo consultado. 
		/// @return El tamanio del bloque, en bytes.
		int ObtenerTamanio(int grupoId);
		
		/// Metodo que reasigna el tamanio de espacio libre destinado a un grupo.
		/// @param grupoId Identificador entero del grupo a actualizarle el tamanio libre.
		/// @param nuevoTamanio Nuevo tamaño libre asignado a ese grupo.
		void AsignarTamanio(int grupoId, int nuevoTamanio);
		
		/// Metodo que devuelve el tamanio actual del archivo entero.
		/// @return El tamanio del archivo donde se guarda el espacio libre.
		long ObtenerTamanioArchivo();
		
		/// Metodo que devuelve un identificador que se encuentre libre para ser utilizado.
		/// @param tamanio Tamanio inicial del bloque pedido. 
		/// @return Id del bloque libre obtenido.
		int ObtenerBloqueLibre(int tamanio);
		
		/// Metodo que persististe en disco la informacion del MapaDeBits.
		/// @param grupoId Identificador entero del grupo liberado. 
		void GuardarArchivo();
		
	};
	
	/// Implementa un mapa de extension a traves de la interfaz de la clase abstracta ManajadorEspacioLibre para el control de espacio libre en un archivo de registros en bloques.
	class MapaExtension : public ManejadorEspacioLibre
	{
		
		private:
		
		int tamanioBloque;
		int elementos[MAX_NUMBLOCKS];
		void Inicializar();
		
		public:
		
		/// Construye una instancia de un manejador de espacio libre basado en la tecnica de mapa de extension.
		/// @param clase Nombre de la clase que representa al archivo a manejar. Se utiliza como clave en toda la capa fisica.
		/// @param tamanioRegistro Tamanio fijo de cada bloque de registros presente en el archivo controlado.	
		MapaExtension(string clase, int tamanioRegistro);
		
		/// Destruye una instancia del MapaExtension y libera todos los recursos.
		~MapaExtension();
		
		// Metodos que implementan los metodos abstractos de ManejadorEspacioLibre
		
		/// Metodo que indica si el grupo esta libre para ser utilizado.
		/// @param grupoId Identificador entero del grupo consultado.
		/// @return true si esta libre, false en caso contrario.
		virtual bool EstaLibre(int grupoId);
		
		/// Metodo que indica si el grupo esta inicializdo, si no lo esta, todos los demas bloques con grupoId superior tampoco lo estaran.
		/// @param grupoId Identificador entero del grupo consultado.
		/// @return true si esta inicializado, false en caso contrario.
		virtual bool EstaInicializado(int grupoId);
		
		/// Metodo que permite especificar un grupo como libre.
		/// @param grupoId Identificador entero del grupo liberado. 
		void Liberar(int grupoId);
		
		/// Metodo que devuelve el tamanio actual del grupo.
		/// @param grupoId Identificador entero del grupo consultado. 
		/// @return El tamanio del bloque, en bytes.
		int ObtenerTamanio(int grupoId);
		
		/// Metodo que reasigna el tamanio de espacio libre destinado a un grupo.
		/// @param grupoId Identificador entero del grupo a actualizarle el tamanio libre.
		/// @param nuevoTamanio Nuevo tamaño libre asignado a ese grupo.
		void AsignarTamanio(int grupoId, int nuevoTamanio);
		
		/// Metodo que devuelve el tamanio actual del archivo entero.
		/// @return El tamanio del archivo donde se guarda el espacio libre.
		long ObtenerTamanioArchivo();
		
		/// Metodo que devuelve un identificador que se encuentre libre para ser utilizado.
		/// @param tamanio Tamanio inicial del bloque pedido. 
		/// @return Id del bloque libre obtenido.
		int ObtenerBloqueLibre(int tamanio);
		
		/// Metodo que persististe en disco la informacion del MapaDeBits.
		/// @param grupoId Identificador entero del grupo liberado. 
		void GuardarArchivo();
		
	};
	
}

#endif
